// 本头文件定义关于消息队列（Message Queue）的使用者（User）的相关操作接口
// User分为两类：生产者，消费者
// 消息队列使用RabbitMQ，故在生产者与消息队列之间存在中间层 ———— 交换机（exchange）

// 生产者行为：将数据传送给指定的exchange。（exchange会自动将消息转发给特定的消息队列）
// 消费者行为：从消息队列获取数据

#pragma once

#include <SimpleAmqpClient/SimpleAmqpClient.h>
#include <iostream>
#include <string>

using std::string;
using namespace AmqpClient;

class MqProducer {
public:
    MqProducer(const string& host, int port, 
               const string& username, const string& password, const string& vhost) 
    : _channel(AmqpClient::Channel::Create(host, port, username, password, vhost))          
    { 
        if (!_channel) {
            std::cerr << "RabbigMq channel for producer faild.\n";
            exit(1);
        }
    }

    // 发送消息；参数：指定交换机名称、路由键、消息内容
    void putMessage(const string& exchange, const string& routingKey, const string& message) {
        // 发送到交换机
        _channel->BasicPublish(exchange, routingKey, AmqpClient::BasicMessage::Create(message));
    }
private:
    AmqpClient::Channel::ptr_t _channel;
};


class MqConsumer {
public:
    MqConsumer(const string& amqpURL, const string& queueName) 
    : _channel(AmqpClient::Channel::CreateFromUri(amqpURL))
    {  
        if (!_channel) {
            std::cerr << "RabbigMq channel for consumer faild.\n";
            exit(1);
        }
        _channel->BasicConsume(queueName);  // channel订阅指定的queue
    }

    // 获取消息
    string getMessage() {
        _envelope = _channel->BasicConsumeMessage();  // 阻塞式

        // 返回消息
        if (_envelope && _envelope->Message()) {
            return _envelope->Message()->Body();
        }
        return string{};
    }
private:
    AmqpClient::Channel::ptr_t _channel;
    AmqpClient::Envelope::ptr_t _envelope;  // 信封，消息的载体
};